1 00:00:00,620 --> 00:00:01,220 Hey there. 2 00:00:01,220 --> 00:00:02,220 Welcome back. 3 00:00:02,240 --> 00:00:10,130 In this lecture I want to talk about the difference between compile time, run time and logical errors 4 00:00:10,130 --> 00:00:15,530 and how we can solve each of these errors, because you are guaranteed to run into each one of these 5 00:00:15,530 --> 00:00:17,930 errors at some point in your code. 6 00:00:18,590 --> 00:00:24,400 A compile time error is an error that is caused by syntax errors. 7 00:00:24,410 --> 00:00:30,200 Remember, syntax is simply the grammar of your code before the scripts in our game can execute, our 8 00:00:30,200 --> 00:00:36,380 computer has to compile or rewrite the code into a language that our computer can understand. 9 00:00:36,380 --> 00:00:40,670 In this case, it has to rewrite our code into a bunch of zeros and ones. 10 00:00:40,670 --> 00:00:43,850 Because our computers read information in binary. 11 00:00:44,090 --> 00:00:50,420 During this compiling process, the compiler looks over the syntax or grammar of our code. 12 00:00:50,450 --> 00:00:54,470 You can think of the compiler as an English teacher grading an essay you've written. 13 00:00:54,470 --> 00:00:59,630 If the compiler spots a mistake, it immediately stops and spits out an error message into the console 14 00:00:59,630 --> 00:01:03,110 saying, hey, you made a grammar mistake here and you need to fix it. 15 00:01:03,410 --> 00:01:08,180 Compile time errors are super easy to fix, and we do not have to worry that much about debugging them 16 00:01:08,180 --> 00:01:10,930 because the compiler will tell us exactly what is wrong. 17 00:01:10,940 --> 00:01:15,800 So all we need to do is just read the error message, find the line where the error was encountered, 18 00:01:15,800 --> 00:01:17,300 and fix our syntax error. 19 00:01:18,270 --> 00:01:21,750 As you can see here, I forgot to fully spell out local. 20 00:01:22,460 --> 00:01:27,470 And I also forgot to add an end statement to close out the scope of this function. 21 00:01:27,980 --> 00:01:34,460 So when this script gets compiled and this code is attempting to be converted into binary, it's going 22 00:01:34,460 --> 00:01:37,530 to immediately see these errors and notify us. 23 00:01:37,550 --> 00:01:40,640 So I'm going to copy this code here. 24 00:01:41,250 --> 00:01:43,020 And I'm going to paste it down here. 25 00:01:43,730 --> 00:01:46,880 And first off, I'm going to keep this section commented out. 26 00:01:47,090 --> 00:01:49,910 But I'm going to try and run this section of my code. 27 00:01:49,910 --> 00:01:51,320 So if I hit run up here. 28 00:01:52,940 --> 00:01:54,470 As you can see, we get our error. 29 00:01:54,470 --> 00:01:55,910 Incomplete statement. 30 00:01:55,940 --> 00:01:58,190 Expected assignment or a function call. 31 00:01:58,190 --> 00:02:00,730 And that was on line 40in our script. 32 00:02:00,740 --> 00:02:06,160 So if we go back we can think oh oops, I forgot to spell out local all the way. 33 00:02:06,170 --> 00:02:06,800 There we go. 34 00:02:06,800 --> 00:02:08,810 Fix that compile time error. 35 00:02:09,050 --> 00:02:13,970 We can also demonstrate this one with the function if we go and try to execute this. 36 00:02:15,040 --> 00:02:18,940 As you can see, we get our problem expected and to close the function. 37 00:02:18,940 --> 00:02:22,120 So we needed that n statement to close the scope of the function. 38 00:02:22,120 --> 00:02:23,200 But we did not add it. 39 00:02:23,200 --> 00:02:27,190 And it said did you forget to close at line 43. 40 00:02:27,280 --> 00:02:32,320 So if we go and check back oops, we forgot to close this function out. 41 00:02:33,340 --> 00:02:36,190 So we can go ahead and add that end statement. 42 00:02:36,190 --> 00:02:36,700 There we go. 43 00:02:36,700 --> 00:02:39,610 We fixed our compile time error. 44 00:02:40,260 --> 00:02:42,900 So compile time errors are really easy to spot. 45 00:02:42,930 --> 00:02:48,480 The Lua linter, which checks over your code while you're typing it, will notify you when you have 46 00:02:48,480 --> 00:02:49,000 an error. 47 00:02:49,020 --> 00:02:50,210 Like when we forgot an end statement. 48 00:02:50,220 --> 00:02:52,230 It's going to highlight all of this as red. 49 00:02:52,970 --> 00:02:57,050 So compile time errors are really easy to fix and you shouldn't worry about them too much. 50 00:02:58,170 --> 00:03:04,590 Now runtime errors are a little bit more involved because they happen after a script gets compiled and 51 00:03:04,590 --> 00:03:06,120 it starts executing. 52 00:03:06,150 --> 00:03:12,210 Runtime errors are not the result of bad grammar in our code, but they are the result of unexpected 53 00:03:12,210 --> 00:03:15,300 conditions that we did not account for in our code. 54 00:03:15,330 --> 00:03:19,950 Runtime errors still give us an error message, but it can take a little bit of time to figure out what 55 00:03:19,950 --> 00:03:22,050 exactly is causing the problem. 56 00:03:22,200 --> 00:03:27,750 A runtime error could be a problem, like trying to divide a number by zero, or attempting to access 57 00:03:27,750 --> 00:03:32,230 an object in our game that does not exist in this function here. 58 00:03:32,250 --> 00:03:39,330 I never created any index value pairs inside of some table, but I'm trying to grab the value there 59 00:03:39,330 --> 00:03:41,440 and add another value to it. 60 00:03:41,460 --> 00:03:47,340 I'm attempting to index this table with an index that does not exist, and add a number to it. 61 00:03:47,670 --> 00:03:53,460 This is not going to error during the compile time of our script, but this will error when we go and 62 00:03:53,460 --> 00:03:54,570 execute the script. 63 00:03:54,570 --> 00:04:00,300 So as an example, if I copy this function and I place it down here in my code, we're going to run 64 00:04:00,300 --> 00:04:01,270 into a problem. 65 00:04:01,290 --> 00:04:03,570 Now the linter is automatically highlighting it for us. 66 00:04:03,570 --> 00:04:07,140 And that's because I accidentally placed an equal sign there. 67 00:04:07,140 --> 00:04:08,070 But there we go. 68 00:04:08,100 --> 00:04:13,620 We're attempting to access the value at some table and add this other index to it, but that's going 69 00:04:13,620 --> 00:04:14,830 to run into a problem. 70 00:04:14,850 --> 00:04:19,920 Currently the linter is not underlining anything as red because our grammar looks good. 71 00:04:19,920 --> 00:04:23,580 But when we go and execute this script, we're going to run into a problem. 72 00:04:23,580 --> 00:04:24,930 So if we hit run here. 73 00:04:25,850 --> 00:04:31,730 As you can see, we get our runtime error and we attempted to perform arithmetic on nil and a number. 74 00:04:32,730 --> 00:04:35,070 So runtime errors are a little bit more involved. 75 00:04:35,070 --> 00:04:39,210 We'll have to go to the line where the error originated from, which would be right here, and we'd 76 00:04:39,210 --> 00:04:44,430 have to think through it and be like, oh, that's because I never added any index value pairs inside 77 00:04:44,430 --> 00:04:45,330 of my table. 78 00:04:45,330 --> 00:04:50,370 So I'm accessing a nil value and attempting to add a number to this nil value. 79 00:04:50,400 --> 00:04:50,970 Oops. 80 00:04:51,030 --> 00:04:52,080 Got to fix that. 81 00:04:53,090 --> 00:04:57,770 Now, the last and most dreaded error in our code is the logical error. 82 00:04:57,800 --> 00:05:01,700 Logical errors are the result of our own mistakes. 83 00:05:01,730 --> 00:05:07,730 Syntactically, the code is correct and it does not get flagged by the compiler, and it does not get 84 00:05:07,730 --> 00:05:09,950 flagged by the interpreter during runtime. 85 00:05:09,980 --> 00:05:16,400 Instead, our code is executing fine, but it's producing a result that we did not expect or intend. 86 00:05:16,430 --> 00:05:21,620 No error messages are given during a logical error, so it's up to us to try and figure out why the 87 00:05:21,620 --> 00:05:23,090 logic in our code is bad. 88 00:05:23,120 --> 00:05:28,070 As an example of a logical error, here we have an if statement that checks for whether or not a player 89 00:05:28,070 --> 00:05:30,110 wants coffee or tea. 90 00:05:30,140 --> 00:05:32,000 They say something, let's say, in the chat. 91 00:05:32,030 --> 00:05:37,820 They say I want coffee, and then we check to see if they have a particular word inside of that string, 92 00:05:37,820 --> 00:05:38,930 such as coffee. 93 00:05:38,960 --> 00:05:43,700 If they say they want coffee, then oops, we're accidentally giving them tea. 94 00:05:44,000 --> 00:05:46,370 Otherwise we're giving them coffee. 95 00:05:46,640 --> 00:05:48,930 So this is not going to error at all. 96 00:05:48,950 --> 00:05:51,680 Our code is going to execute just as we've written it out. 97 00:05:51,680 --> 00:05:55,580 But the outcome of this code is not what we expect or intend. 98 00:05:55,610 --> 00:05:59,900 We wanted to give the player a coffee, but instead we're accidentally giving them tea. 99 00:06:01,060 --> 00:06:06,160 Logical errors are the most difficult errors to try and fix, especially in large projects, because 100 00:06:06,160 --> 00:06:12,280 we can't really see what lines are being executed or flagged by our interpreter or compiler, like a 101 00:06:12,280 --> 00:06:14,470 runtime or compile time error would. 102 00:06:14,830 --> 00:06:20,410 Now, one way we could diagnose a runtime and logical errors are by using something called breakpoints 103 00:06:20,410 --> 00:06:22,600 and print statements in our code. 104 00:06:22,720 --> 00:06:28,570 We can use print statements as a triggering device that lets us know, hey, this section of code executed 105 00:06:28,570 --> 00:06:32,560 okay, and if it didn't, I wouldn't have printed out this message into the console. 106 00:06:32,590 --> 00:06:37,840 So, for example, if somebody wanted coffee, we could add different print statements in here to see 107 00:06:37,840 --> 00:06:39,760 what exactly is executing. 108 00:06:39,760 --> 00:06:44,530 And then based on the execution of those print statements, we could figure out, oh, oops, I'm accidentally 109 00:06:44,530 --> 00:06:47,300 calling the wrong functions in these sections of the if statements. 110 00:06:47,320 --> 00:06:50,350 Let me go ahead and flip those around and fix my logical error. 111 00:06:50,440 --> 00:06:56,350 So just having print statements in your code allow you to see what section is being executed because 112 00:06:56,350 --> 00:07:01,660 it'll appear in the console, and it'll help give you a better idea of what exactly is being executed 113 00:07:01,660 --> 00:07:02,500 in your code. 114 00:07:02,530 --> 00:07:07,780 We can also do the same thing with breakpoints, and a breakpoint is where we can mark a section in 115 00:07:07,780 --> 00:07:14,200 our code where once the interpreter hits that mark, we stop the game and we hop back into the script 116 00:07:14,200 --> 00:07:19,600 and we can go ahead and execute the code ourselves line by line, to see what exactly is happening. 117 00:07:20,150 --> 00:07:25,250 Now, a great analogy to sum up all of these errors is to imagine yourself as a marathon runner. 118 00:07:25,370 --> 00:07:30,740 A compile time error would be equivalent to you surveying a marathon course before attending it. 119 00:07:30,770 --> 00:07:35,360 You check for any problems and check to see if there are any major hazards that can cause big injury 120 00:07:35,360 --> 00:07:36,200 in the course. 121 00:07:36,230 --> 00:07:40,160 If so, you flag those hazards before running in the race. 122 00:07:40,190 --> 00:07:45,230 Now a runtime error would be equivalent to you verifying the course was safe and then running in the 123 00:07:45,230 --> 00:07:45,890 marathon. 124 00:07:45,890 --> 00:07:50,150 But then let's say all of a sudden the weather went bad and now you're in a thunderstorm and you get 125 00:07:50,150 --> 00:07:51,110 struck by lightning. 126 00:07:51,140 --> 00:07:56,390 The course track was okay, but we forgot to account for the external condition and variables that led 127 00:07:56,390 --> 00:07:58,190 us to being struck by lightning. 128 00:07:58,460 --> 00:08:04,190 The last type of error, a logical error, is when we account for all external conditions, and we found 129 00:08:04,190 --> 00:08:05,780 the running track to be safe. 130 00:08:05,780 --> 00:08:10,880 But let's say there's a fork in the running track, and we make the mistake and run down the wrong path 131 00:08:10,880 --> 00:08:11,750 of the course. 132 00:08:11,780 --> 00:08:14,540 Now we have ended up in an outcome that was unexpected. 133 00:08:14,540 --> 00:08:18,800 We are lost and on the wrong trail, and that was our own fault. 134 00:08:19,160 --> 00:08:22,550 So you should now know about the three types of errors in our code. 135 00:08:22,550 --> 00:08:26,130 And we're going to learn about how to debug errors using breakpoints. 136 00:08:26,150 --> 00:08:31,160 So to quickly demonstrate breakpoints here I'm just going to create a for loop that loops five times. 137 00:08:32,510 --> 00:08:36,350 And I'm going to do in this for loop is just print out I into the console. 138 00:08:36,350 --> 00:08:38,840 And then afterwards let's say we have some other random code. 139 00:08:38,840 --> 00:08:42,520 And eventually there's an error in this code that we can't really understand what's happening. 140 00:08:42,530 --> 00:08:49,310 I'm not going to make a super complex example, but to throw our own custom error, we can use the error 141 00:08:49,310 --> 00:08:54,770 function, which allows us to send a message into the console and halts the thread of execution. 142 00:08:54,770 --> 00:08:56,210 So I could say. 143 00:08:56,210 --> 00:08:59,870 And here we encountered some error. 144 00:09:00,020 --> 00:09:04,460 So once the interpreter goes through and executes and hits this point, it's going to halt the thread 145 00:09:04,460 --> 00:09:06,110 and throw an error here. 146 00:09:06,770 --> 00:09:08,480 Now to go ahead and use breakpoints. 147 00:09:08,480 --> 00:09:14,390 What I'm going to do is insert one just before my for loop, and to do that we go to the line where 148 00:09:14,390 --> 00:09:18,170 we would like to insert the breakpoint and we click right next to the number. 149 00:09:18,170 --> 00:09:22,760 So if I click here we have now inserted this red dot which is our breakpoint. 150 00:09:22,760 --> 00:09:27,200 If we no longer need this breakpoint, we can go ahead and right click it. 151 00:09:27,200 --> 00:09:30,890 And we can go ahead and either disable it or delete this breakpoint. 152 00:09:30,890 --> 00:09:34,970 But I want to keep this breakpoint here because I'm going to show you how we can use these breakpoints. 153 00:09:34,970 --> 00:09:41,060 So when we go and run our game, immediately we have jumped into our script because the interpreter 154 00:09:41,060 --> 00:09:46,400 has reached our breakpoint and is now telling us that we need to go ahead and manually go through the 155 00:09:46,400 --> 00:09:48,680 script after our breakpoint. 156 00:09:48,680 --> 00:09:52,760 So this yellow arrow signifies the next line of code we're about to execute. 157 00:09:52,760 --> 00:09:58,190 And to use these breakpoints and debug our code, we go up to the debugger section here in the script 158 00:09:58,220 --> 00:10:03,470 tag, and we have three buttons such as step into, step over, and step Out. 159 00:10:03,710 --> 00:10:09,170 The step over button allows me to skip going into a function, in case I don't want to see how it is. 160 00:10:09,170 --> 00:10:11,390 Run line by line and step out. 161 00:10:11,390 --> 00:10:12,950 Lets me jump out of a function. 162 00:10:12,950 --> 00:10:15,860 If I don't wish to see how the rest of the function executes. 163 00:10:15,950 --> 00:10:20,150 So to continue executing through my code, I'm just going to keep pressing the step into button. 164 00:10:20,150 --> 00:10:21,590 So we're going to hit step into. 165 00:10:21,620 --> 00:10:23,000 We hit the print statement. 166 00:10:23,000 --> 00:10:25,160 We're going to execute that print statement. 167 00:10:25,160 --> 00:10:27,410 As you can see when printed into the console. 168 00:10:27,410 --> 00:10:30,230 And then we're going to repeat this process in our loop. 169 00:10:31,890 --> 00:10:34,140 And we're going to execute this for loop five times. 170 00:10:34,140 --> 00:10:38,970 And eventually we hop out of that for loop and we move to our next line here, which is our error. 171 00:10:38,970 --> 00:10:43,230 And then if we execute this line right here, there we go. 172 00:10:43,230 --> 00:10:45,980 We encountered our error and we're done debugging. 173 00:10:45,990 --> 00:10:51,240 So these breakpoints helped us to go line by line through our script and eventually understand where 174 00:10:51,240 --> 00:10:57,600 exactly our error is coming from, and also understand what happened previous to that error occurring. 175 00:10:57,960 --> 00:11:03,570 This was a fairly rough example, but you'll find breakpoints useful in more complex situations, especially 176 00:11:03,570 --> 00:11:06,330 when you don't have a good idea of how your code is executing. 177 00:11:07,310 --> 00:11:11,720 Now I'm just going to delete this breakpoint and we're going to go ahead and move on. 178 00:11:13,080 --> 00:11:17,370 Because now I want to talk about how we can handle errors inside of our code. 179 00:11:17,400 --> 00:11:23,070 There may be times when you have a piece of code that's going to error, and fixing that error is out 180 00:11:23,070 --> 00:11:24,180 of your control. 181 00:11:24,210 --> 00:11:30,360 As an example, there are dozens of functions in the Roblox API that are used to fetch information from 182 00:11:30,360 --> 00:11:31,590 Roblox servers. 183 00:11:31,620 --> 00:11:37,560 These functions are not guaranteed to succeed all the time due to external problems out of our control, 184 00:11:37,560 --> 00:11:40,140 such as a server going down or some other event. 185 00:11:40,170 --> 00:11:45,420 Because of this, these functions have the possibility of causing an error if they do error. 186 00:11:45,450 --> 00:11:49,140 We do not want that error to halt the execution of our scripts. 187 00:11:49,170 --> 00:11:55,890 This is where a function called pcall comes into play and its name is short for protected call. 188 00:11:56,340 --> 00:12:01,770 So Pcall is a default function inside of Lua that allows us to handle a function. 189 00:12:01,770 --> 00:12:07,650 And in case that function errors, instead of halting the threat of execution, it's going to return 190 00:12:07,680 --> 00:12:12,000 a value of either true or false, telling us whether or not it's successfully executed. 191 00:12:12,000 --> 00:12:12,930 The function. 192 00:12:13,380 --> 00:12:18,930 And here it says runs the provided function and catches any error it throws, returning the function 193 00:12:18,930 --> 00:12:20,850 success and its result. 194 00:12:21,120 --> 00:12:24,090 So to demonstrate pcall we get to make two variables. 195 00:12:24,090 --> 00:12:28,950 One I'm going to call success, and then to declare another variable on the same line, I'm going to 196 00:12:28,950 --> 00:12:31,920 put a comma and I'm going to call this one result. 197 00:12:31,920 --> 00:12:37,650 And it's going to be equal to our Pcall function, because our Pcall function is automatically going 198 00:12:37,650 --> 00:12:43,080 to return a boolean of whether or not we were successful in executing the function that we passed to 199 00:12:43,080 --> 00:12:44,370 the call function. 200 00:12:44,460 --> 00:12:50,670 And then the result returns either the error message from that function, or any other values that get 201 00:12:50,670 --> 00:12:54,030 returned from the function we pass to the call function. 202 00:12:54,670 --> 00:12:58,510 So I'm going to put in here is a lambda function. 203 00:12:58,510 --> 00:13:04,030 And a lambda function or an anonymous function is simply a function that has no identifier. 204 00:13:04,060 --> 00:13:05,920 The purpose of this function. 205 00:13:06,910 --> 00:13:08,900 Is just to execute here only. 206 00:13:08,900 --> 00:13:14,420 And since there is no identifier, I can't type out the name and execute it elsewhere in my code. 207 00:13:14,420 --> 00:13:16,270 It only exists right here. 208 00:13:16,280 --> 00:13:20,300 So an anonymous function is simply one that has no identifier. 209 00:13:20,660 --> 00:13:26,210 And inside of this lambda function, what I'm going to do is raise an error, and I'm just going to 210 00:13:26,210 --> 00:13:30,560 say something like some error caught by call. 211 00:13:31,330 --> 00:13:36,850 So when this p call function executes and it goes into execute this function, when this error is hit, 212 00:13:36,850 --> 00:13:39,160 the call function is going to handle that. 213 00:13:39,160 --> 00:13:42,640 And it's going to return false telling us that the function errored. 214 00:13:42,640 --> 00:13:46,000 And then the result is going to be our error message. 215 00:13:46,120 --> 00:13:53,860 So then we can go ahead and print success and result into the console, because the Pcall function is 216 00:13:53,860 --> 00:13:58,770 going to prevent the main thread of execution from halting when this error is reached. 217 00:13:58,780 --> 00:14:00,700 And I misspelled success here. 218 00:14:00,700 --> 00:14:01,690 So let me fix that. 219 00:14:02,420 --> 00:14:04,940 And now we can go ahead and run our script. 220 00:14:05,650 --> 00:14:06,310 And there we go. 221 00:14:06,310 --> 00:14:11,460 We get the value of false, which signifies that the function did not execute successfully. 222 00:14:11,470 --> 00:14:13,510 And here we get our error message. 223 00:14:13,540 --> 00:14:17,950 On line 41 we had some error caught by our pcall. 224 00:14:19,320 --> 00:14:24,210 So this was just a quick lecture on the different errors in Lua and how we can handle those errors using 225 00:14:24,210 --> 00:14:25,510 the Pcall function. 226 00:14:25,530 --> 00:14:31,830 You reach the end of Lua basics, and now it is time to start interacting with our game and making fun 227 00:14:31,830 --> 00:14:33,870 stuff in Roblox studio. 228 00:14:33,960 --> 00:14:36,510 I will go ahead and see you in the next lecture.